home *** CD-ROM | disk | FTP | other *** search
- /* implementation file for delete element function for
- sorted list data structure. implemented as an AVL tree. */
-
- #include <string.h>
-
- #include "align.h"
- #include "stckallc.h"
- #include "sortlist.h"
- #include "slintrnl.h"
-
- /* function which returns a pointer to the pointer to the
- node containing a particular element */
- static void **find_node
- (
- /* pointer to sorted list to containing element */
- SORT_LIST *sl,
- /* element to find */
- const void *elem
- )
- {
- /* parent of node containing element */
- void *parent_node;
-
- int compare_result, which_branch;
- void *p = sl->tree;
-
- parent_node = (void *) 0;
-
- for ( ; ; )
- {
- /* compare with current element */
- compare_result = (*(sl->elem_elem_compare))(elem, ELEM_IN_NODE(p));
-
- if (compare_result == 0)
- /* done */
- {
- if (parent_node)
- return(&(NODE(parent_node)->branch[which_branch]));
- else
- /* element in root node */
- return(&(sl->tree));
- }
-
- which_branch =
- compare_result > 0 ? GREATER_BRANCH : LESS_BRANCH;
-
- /* proceed to next subtree */
- parent_node = p;
- p = NODE(p)->branch[which_branch];
-
- } /* for */
-
- }
-
- /* deallocate a given node */
- static void free_node
- (
- /* pointer to sorted list in whose node allocation stack the node
- appears */
- SORT_LIST *sl,
- /* pointer to node to free */
- void *node
- )
- {
- void *last_alloc = look_alloc_stack(&(sl->node_alloc_stack));
-
- if (node != last_alloc)
- {
- /* copy the node at the top of the allocation stack to
- the memory occupied by the node to be deleted. */
- memcpy(node, last_alloc,
- N_UNITS_IN_NODE_PREFIX * sizeof(ALIGN_TYPE) + sl->elem_size);
-
- /* find the pointer in the tree to the node that is at the
- top of the allocation stack and reset it to the copy just
- made. */
- *find_node(sl, ELEM_IN_NODE(last_alloc)) = node;
- }
-
- /* dellocate the memory for the node at the top of the
- allocation stack */
- free_alloc_stack(&(sl->node_alloc_stack));
-
- return;
- }
-
- /* remove max. or min. node in a tree. returns non-zero
- if the depth of the tree was reduced. recursive. */
- static int remove_extreme
- (
- /* pointer to pointer to tree to delete from */
- void **tree,
- /* LESS_BRANCH for min., GREATER_BRANCH for max. */
- int which_branch,
- /* pointer to variable to set to node that was removed */
- void **node
- )
- {
- if (!(NODE(*tree)->branch[which_branch]))
- {
- *node = *tree;
- *tree = NODE(*tree)->branch[OTHER(which_branch)];
- return(1);
- }
- else if (remove_extreme(&(NODE(*tree)->branch[which_branch]),
- which_branch, node))
- /* subtree was reduced in depth */
- {
- int i = NODE(*tree)->balance;
-
- NODE(*tree)->balance = (char)
- (i + (which_branch == LESS_BRANCH ? 1 : -1));
-
- /* if shorter branch was reduced, tree needs to be
- rebalanced */
- if (which_branch == GREATER_BRANCH)
- i = -i;
- if (i == 1)
- i = balance_tree(tree);
-
- return(i);
- }
- else
- /* if branch wasn't reduced in depth, tree wasn't reduced in
- depth */
- return(0);
- }
-
- /* unchanging parameters to remove_elem() */
- typedef struct
- {
- /* key of element to remove */
- const void *key;
- /* key - element compare function */
- int (*key_elem_compare)(const void *key, const void *elem);
- /* set to node containng element. needs to be deallocated. if
- pointer is set to null, no element with the given key found */
- void *node;
- }
- RE_PARAM;
-
- /* remove element with given key from tree. returns non-zero
- if the depth of the tree was reduced. recursive. */
- static int remove_elem
- (
- /* pointer to pointer to tree to delete from */
- void **tree,
- /* pointer to unchanging parameters */
- RE_PARAM *param
- )
- {
- int i, j;
-
- if (!*tree)
- {
- param->node = (void *) 0;
- return(0);
- }
-
- i = (*(param->key_elem_compare))(param->key, ELEM_IN_NODE(*tree));
-
- if (i == 0)
- /* found the element to delete */
- {
- void *p;
-
- if (!(NODE(*tree)->branch[LESS_BRANCH] ||
- NODE(*tree)->branch[GREATER_BRANCH]))
- /* no subtrees - just prune the node */
- {
- param->node = *tree;
- *tree = (void *) 0;
- return(1);
- }
-
- /* have to move the extreme node from a subtree into
- this position. get the extreme node from the deeper
- subtree if possible. */
- i = NODE(*tree)->balance > 0 ? GREATER_BRANCH : LESS_BRANCH;
- j = remove_extreme(&(NODE(*tree)->branch[i]), OTHER(i), &p);
- memcpy(p, *tree, sizeof(NODE_PREFIX));
- param->node = *tree;
- *tree = p;
- }
- else /* proceed to next level */
- {
- i = i > 0 ? GREATER_BRANCH : LESS_BRANCH;
- j = remove_elem(&(NODE(*tree)->branch[i]), param);
- }
-
- if (j)
- /* subtree was reduced in depth */
- {
- j = NODE(*tree)->balance;
-
- /* adjust balance factor */
- NODE(*tree)->balance = (char) (j + (i == LESS_BRANCH ? 1 : -1));
-
- /* if short subtree was reduced, need to rebalance */
- if (i == GREATER_BRANCH)
- j = -j;
- if (j == 1)
- j = balance_tree(tree);
- }
-
- return(j);
- }
-
- /* delete the element with the given key. returns SL_SUCCESS if
- element is found. returns SL_NO_MATCH if element not found. */
- SL_RESULT delete_sort_list
- (
- /* sorted list to search */
- SORT_LIST *sl,
- /* key to match */
- const void *key,
- /* pointer to variable to receive a copy of the element searched
- for. if this pointer is null, the element is simply deleted
- without being copied. */
- void *elem
- )
- {
- RE_PARAM param;
-
- param.key = key;
- param.key_elem_compare = sl->key_elem_compare;
-
- remove_elem(&(sl->tree), ¶m);
-
- if (!param.node)
- return(SL_NO_MATCH);
-
- if (elem)
- memcpy(elem, ELEM_IN_NODE(param.node), sl->elem_size);
-
- /* deallocate node */
- free_node(sl, param.node);
-
- return(SL_SUCCESS);
- }
-